
#ifndef _CS_MEMORY_H_
#define _CS_MEMORY_H_
#include <assert.h>

class csMemory
{
protected:
	struct Node
	{
		DWORD dwTotal;	// total size of the buffer in bytes
		DWORD dwSize;	// data size in the buffer in bytes
		BYTE* pBuffer;
		Node* pNext;
		Node()
		{
			dwTotal = 0;
			dwSize = 0;
			pBuffer = NULL;
			pNext = NULL;
		}
	};
	Node*	m_pHead;
	Node*	m_pNode;

	DWORD	m_dwBlockSize;
public:
	csMemory(DWORD dwBlockSize = 0)
	{
		m_pHead = NULL;
		m_pNode = NULL;
		m_dwBlockSize = dwBlockSize;
	}
	virtual ~csMemory()
	{
		Clear();
	}
	DWORD	GetTotalSize()
	{
		DWORD dwSize = 0;
		Node* pNode = m_pHead;
		while(pNode)
		{
			dwSize += pNode->dwSize;
			if(pNode == m_pNode)
				break;
			pNode = pNode->pNext;
		}
		return dwSize;
	}
	BOOL	InsertData(const BYTE* pBuffer,DWORD dwSize)
	{
		Node* pTail = m_pNode;
		while(pBuffer && dwSize > 0)
		{
			if(m_pNode == NULL)
			{
				m_pNode = new Node;
				if(m_pNode == NULL)
					return FALSE;

				if(m_pHead == NULL)
					m_pHead = m_pNode;
				if(pTail)
					pTail->pNext = m_pNode;
				if(m_dwBlockSize > 0)
				{
					m_pNode->dwTotal = m_dwBlockSize;
					m_pNode->dwSize = 0;
					m_pNode->pBuffer = new BYTE[m_dwBlockSize];
				}
				else
				{
					m_pNode->dwTotal = dwSize;
					m_pNode->dwSize = 0;
					m_pNode->pBuffer = new BYTE[dwSize];
				}
				if(m_pNode->pBuffer == NULL)
				{
					assert(FALSE);
					delete m_pNode;
					m_pNode = NULL;
					return FALSE;
				}
			}
			DWORD dwLess = m_pNode->dwTotal - m_pNode->dwSize;
			if(dwLess <= 0)
			{
				pTail = m_pNode;
				m_pNode = m_pNode->pNext;
				continue;
			}
			else
			{
				BYTE* pBegin = m_pNode->pBuffer + m_pNode->dwSize;
				if(dwLess >= dwSize)
				{
					memcpy(pBegin,pBuffer,dwSize);
					m_pNode->dwSize += dwSize;
					return TRUE;
				}
				else
				{
					memcpy(pBegin,pBuffer,dwLess);
					m_pNode->dwSize += dwLess;
					pBuffer += dwLess;
					dwSize -= dwLess;
					
					pTail = m_pNode;
					m_pNode = m_pNode->pNext;
					continue;
				}
			}
		}
		return FALSE;
	}
	DWORD	OutputData(BYTE* pBuffer,DWORD dwSize)
	{
		if(pBuffer && dwSize >= GetTotalSize())
		{
			dwSize = 0;
			Node* pNode = m_pHead;
			while(pNode)
			{
				memcpy(pBuffer,pNode->pBuffer,pNode->dwSize);
				pBuffer += pNode->dwSize;
				dwSize += pNode->dwSize;
				if(pNode == m_pNode)
					break;
				pNode = pNode->pNext;
			}
			return dwSize;
		}
		return 0;
	}
	void	Reset()
	{
		m_pNode = m_pHead;
		Node* pNode = m_pHead;
		while(pNode)
		{
			pNode->dwSize = 0;
			pNode = pNode->pNext;
		}
	}
	void	Clear()
	{
		while(m_pHead)
		{
			Node* pNode = m_pHead;
			m_pHead = m_pHead->pNext;
			delete[] pNode->pBuffer;
			delete pNode;
		}
		m_pNode = NULL;
	}
};


#endif// _CS_MEMORY_H_
